home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / mailbox2.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  42KB  |  1,842 lines

  1. /* NOTE: because of size, the previous 'mailbox.c' has been
  2.  * split in 3 parts:
  3.  * mboxcmd.c, containing the 'mbox' subcommands,
  4.  * mailbox.c, containing some user mailbox commands, and
  5.  * mailbox2.c, containing the remaining user commands.
  6.  * 921125 - WG7J
  7.  */
  8. /* There are only two functions in this mailbox code that depend on the
  9.  * underlying protocol, namely mbx_getname() and dochat(). All the other
  10.  * functions can hopefully be used without modification on other stream
  11.  * oriented protocols than AX.25 or NET/ROM.
  12.  *
  13.  * SM0RGV 890506, most work done previously by W9NK
  14.  *
  15.  *** Changed 900114 by KA9Q to use newline mapping features in stream socket
  16.  *      interface code; everything here uses C eol convention (\n)
  17.  *
  18.  *      Numerous new commands and other changes by SM0RGV, 900120
  19.  *
  20.  * Gateway function now support outgoing connects with the user's call
  21.  * with inverted ssid. Users can connect to system alias as well...
  22.  * See also several mods in socket.c,ax25.c and others
  23.  * 11/15/91, WG7J/PA3DIS
  24.  *
  25.  * Userlogging, RM,VM and KM commands, and R:-line interpretation
  26.  * added 920307 and later, Johan. K. Reinalda, WG7J/PA3DIS
  27.  *
  28.  * Inactivity timeout-disconnect added 920325 and later - WG7J
  29.  *
  30.  */
  31. #include <stdio.h>
  32. #include <time.h>
  33. #include <ctype.h>
  34. #ifdef MSDOS
  35. #include <alloc.h>
  36. #endif
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #ifdef  UNIX
  40. #include <sys/types.h>
  41. #include <sys/stat.h>
  42. #endif
  43. #include "global.h"
  44. #include "config.h"
  45. #include "timer.h"
  46. #include "proc.h"
  47. #include "socket.h"
  48. #include "usock.h"
  49. #include "session.h"
  50. #include "smtp.h"
  51. #include "dirutil.h"
  52. #include "telnet.h"
  53. #include "ftp.h"
  54. #include "ftpserv.h"
  55. #include "commands.h"
  56. #include "netuser.h"
  57. #include "files.h"
  58. #include "bm.h"
  59. #include "pktdrvr.h"
  60. #include "ax25.h"
  61. #include "mailbox.h"
  62. #include "ax25mail.h"
  63. #include "nr4mail.h"
  64. #include "cmdparse.h"
  65. #include "mailfor.h"
  66. #include "authent.h"
  67.  
  68. #ifdef MAILBOX
  69.  
  70. /* Log all gateway connects to the logfile - WG7J */
  71. #define GWTRACE 1
  72.  
  73. /* By setting the fp to NULL, we can check in exitbbs()
  74.  * wether a tempfile has been closed or not - WG7J
  75.  */
  76. #define MYFCLOSE(x) { fclose(x); x = (FILE *) 0; }
  77.  
  78. /*
  79. #define MBDEBUG
  80. */
  81.  
  82. extern time_t StartTime;
  83. extern char Myalias[];
  84.  
  85. extern struct mbx *Mbox;
  86. extern int BbsUsers;
  87. extern int Totallogins;
  88. extern char *Mtmsg;
  89. extern int MAttended;
  90. extern unsigned Maxlet;
  91. extern char Mbpasswd[];
  92.  
  93. extern int MbSent;
  94. extern int MbRead;
  95. extern int MbRecvd;
  96. #ifdef MBFWD
  97. extern int MbForwarded;
  98. #endif
  99.  
  100. extern char Noperm[];
  101. extern char Nosock[];
  102. extern char MboxId[];
  103.  
  104. extern char Loginbanner[];
  105. extern char Howtoend[];
  106. extern char CcLine[];
  107. extern char Mbwelcome[];
  108. extern char Mbbanner[];
  109. extern char Mbwarning[];
  110. extern char CurUsers[];
  111. extern char MsgAborted[];
  112. extern char Mbmenu[];
  113. extern char Mbnrid[];
  114. extern char Longmenu[];
  115.  
  116. extern void gw_alarm __ARGS((void *p));
  117. extern void gw_input __ARGS((int s,void *notused,void *p));
  118. extern void gw_superv __ARGS((int null,void *proc,void *p));
  119. extern int dombusers __ARGS((int argc,char *argv[],void *p));
  120. extern int dombpast __ARGS((int argc,char *argv[],void *p));
  121. extern int doarea __ARGS((int argc,char *argv[],void *p));
  122. extern int dombstatus __ARGS((int argc,char *argv[],void *p));
  123. extern int dombmailstats __ARGS((int argc,char *argv[],void *p));
  124. extern int dombcallbook __ARGS((int argc,char *argv[],void *p));
  125. extern int dombarp __ARGS((int argc,char *argv[],void *p));
  126. extern int doipheard __ARGS((int argc,char *argv[],void *p));
  127. static void dombconnecthelp __ARGS((void));
  128.  
  129.  
  130. extern int Mbnewmail;
  131. extern int Usenrid;
  132. extern int MBSecure;
  133. extern int Mbsendquery;
  134. #ifdef MBXTDISC
  135. extern int32 Mbtdiscinit;
  136. #endif
  137.  
  138. /*Enlighten them a bit!
  139.  */
  140. static
  141. void
  142. dombconnecthelp() {
  143. #ifdef CONVERS
  144.     tputs("Syntax: 'C                for Conference bridge\n"
  145. #ifdef NETROM
  146.       "        'C <node>'        for NET/ROM connects\n"
  147. #endif
  148.       "        'C <port> <call>' for AX.25 connects\n"
  149. #ifdef CALLBOOK
  150.       "        'CA               to access internet callbook\n"
  151. #endif
  152.       "\n");
  153. #else /* CONVERS */
  154. #ifdef NETROM
  155.     tputs("Syntax: 'C <node>'        for NET/ROM connects\n"
  156.       "        'C <port> <call>' for AX.25 connects\n"
  157. #else
  158.     tputs("Syntax: 'C <port> <call>' for AX.25 connects\n"
  159. #endif /* NETROM */
  160. #ifdef CALLBOOK
  161.       "        'CA               to access internet callbook\n"
  162. #endif
  163.       "\n");
  164. #endif /* CONVERS */
  165. }
  166.  
  167.  
  168. #ifdef NETROM
  169.  
  170. int
  171. #ifdef PROTOTYPES
  172. dombnrnodes(int argc,char **argv,void *p)
  173. #else
  174. dombnrnodes(argc,argv,p)
  175. int argc;
  176. char *argv[];
  177. void *p;
  178. #endif
  179. {
  180.     struct mbx *m;
  181.  
  182.     m = (struct mbx *)p;
  183.  
  184.     if(argc < 2)
  185.         return doroutedump();
  186.     if(*argv[1] == '*')
  187.     argc = 1;
  188.     return dorouteinfo(argc,argv,p);
  189. }
  190. #endif
  191.  
  192.  
  193. #ifdef MAILCMDS
  194. int
  195. #ifdef PROTOTYPES
  196. dosid(int argc,char **argv,void *p)
  197. #else
  198. dosid(argc,argv,p)
  199. int argc;
  200. char *argv[];
  201. void *p;
  202. #endif
  203. {
  204.     struct mbx *m;
  205.     char *cp;
  206.  
  207.     m = (struct mbx *)p;
  208.     if(argc == 1)
  209.         return 1;
  210.     if(argv[1][strlen(argv[1]) - 1] != ']') /* must be an SID */
  211.         return 1;
  212. #ifdef notdef
  213.     if(m->stype == 'Z' && strncmp(argv[1],"cz",2) == 0) {
  214.     /* LAN-LINK's [ZCZ] */
  215.     m->sid |= MBX_LL;
  216.     return 0;
  217.     }
  218. #endif
  219.     /* Other bbs's */
  220.     m->sid = MBX_SID;
  221.  
  222.     /* Now check to see if this is an RLI board.
  223.      * As usual, Hank does it a bit differently from
  224.      * the rest of the world.
  225.      */
  226.     if(m->stype == 'R' && strncmp(argv[1],"li",2) == 0)/* [RLI] at a minimum */
  227.         m->sid |= MBX_RLI_SID;
  228.     /* Or maybe it is F6FBB ? */
  229.     else if(m->stype == 'F')
  230.     m->sid |= MBX_FBB;
  231.     /* Check to see if the BBS supports a kludge called "hierarchical
  232.      * routing designators."
  233.      *
  234.      * No need to check for ']' -- it must be there or this is not
  235.      * a valid mbox id -- it is checked earlier (fix de OH3LKU)
  236.      *
  237.      * Sid format is [BBSTYPE-VERSION-OPTIONS]
  238.      * check for LAST -, to allow for version portion. - WG7J
  239.      */
  240.     if((cp = strrchr(argv[1],'-')) != NULLCHAR) {
  241.     cp++;
  242.     /* Okay, now parse the options */
  243.     if((strchr(cp,'h') != NULLCHAR) && (strchr(cp,'$') != NULLCHAR))
  244.         m->sid |= MBX_HIER_SID;
  245.     if(strchr(cp,'m') != NULLCHAR)
  246.         m->sid |= MBX_MID;
  247.     }
  248.     return 0;
  249. }
  250. #endif
  251.  
  252. int
  253. dombescape(argc,argv,p)
  254. int argc;
  255. char *argv[];
  256. void *p;
  257. {
  258.     struct mbx *m;
  259.  
  260.     m = (struct mbx *)p;
  261.     if(argc < 2){
  262.     tprintf("Escape is %s, Escape char: ",
  263.         (m->privs & NO_ESCAPE) ? "OFF" : "ON");
  264.         if(m->escape < 32)
  265.             tprintf("CTRL-%c\n",m->escape+'A'-1);
  266.         else
  267.             tprintf("'%c'\n",m->escape);
  268.         return 0;
  269.     }
  270.     if(strlen(argv[1]) > 1) {
  271.         if(isdigit(*argv[1]))
  272.             m->escape = (char) atoi(argv[1]);
  273.     else {
  274.         if( !strnicmp(argv[1],"OFF",3) || !strnicmp(argv[1],"dis",3) )
  275.         m->privs |= NO_ESCAPE;
  276.         else
  277.         m->privs &= ~NO_ESCAPE;
  278.     }
  279.     } else
  280.         m->escape = *argv[1];
  281.     return 0;
  282. }
  283.  
  284. int
  285. #ifdef PROTOTYPES
  286. dodownload(int argc,char **argv,void *p)
  287. #else
  288. dodownload(argc,argv,p)
  289. int argc;
  290. char *argv[];
  291. void *p;
  292. #endif
  293. {
  294.     struct mbx *m;
  295.     FILE *fp;
  296.     char *file;
  297.  
  298.     m = (struct mbx *)p;
  299.     file = pathname(m->path,argv[1]);
  300.     if(!permcheck(m->path,m->privs,RETR_CMD,file)){
  301.     tputs(Noperm);
  302.     mail_error("%s: download denied\n",m->name);
  303.         return 0;
  304.     }
  305. #ifdef TIPMAIL
  306. #ifdef XMODEM
  307.     if (m->stype=='X') { 
  308.     if (m->type==TIP_LINK){   /* xmodem send tip only */
  309.         m->state = MBX_XMODEM_TX;
  310. #ifdef MBXTDISC
  311.         /* disable the mbox inactivity timeout timer - WG7J */
  312.         stop_timer(&m->tdisc);
  313. #endif
  314.         doxmodem('S',file,m);
  315.         return 0;
  316.     } else {
  317.         tputs("Xmodem on TIP connects only\n");
  318.         return 0;
  319.     }
  320.     }
  321. #endif
  322. #endif
  323.     m->state = MBX_DOWNLOAD;
  324.     if((fp = fopen(file,READ_TEXT)) == NULLFILE)
  325.         tprintf("Can't open \"%s\": %s\n",file,sys_errlist[errno]);
  326.     else {
  327. #ifdef MBXTDISC
  328.     /* disable the mbox inactivity timeout timer - WG7J */
  329.     stop_timer(&m->tdisc);
  330. #endif
  331.     if(m->stype == 'U'){            /* uuencode ? */
  332.             fclose(fp);
  333.             fp = fopen(file,READ_BINARY);   /* assume non-ascii */
  334.             uuencode(fp,m->user,file);
  335.         } else
  336.             sendfile(fp,m->user,ASCII_TYPE,0);
  337.     }
  338.     free(file);
  339.     fclose(fp);
  340.     return 0;
  341. }
  342.  
  343. int
  344. #ifdef PROTOTYPES
  345. dombupload(int argc,char **argv,void *p)
  346. #else
  347. dombupload(argc,argv,p)
  348. int argc;
  349. char *argv[];
  350. void *p;
  351. #endif
  352. {
  353.     struct mbx *m;
  354.     FILE *fp;
  355.     char *file;
  356.  
  357.     m = (struct mbx *)p;
  358.     file = pathname(m->path,argv[1]);
  359.     if(!permcheck(m->path,m->privs,STOR_CMD,file)){
  360.     tputs(Noperm);
  361.     mail_error("%s: upload denied\n",m->name);
  362.         return 0;
  363.     }
  364. #ifdef TIPMAIL
  365. #ifdef XMODEM
  366.     if (m->stype=='X'){ 
  367.     if (m->type==TIP_LINK){   /* xmodem receive tip only */
  368.             m->state = MBX_XMODEM_RX;
  369. #ifdef MBXTDISC
  370.         /* disable the mbox inactivity timeout timer - WG7J */
  371.             stop_timer(&m->tdisc);   
  372. #endif
  373.             doxmodem('R',file,m);
  374.             return 0;
  375.         } else {
  376.         tputs("Xmodem on TIP connects only\n");
  377.             return 0;
  378.         }
  379.     }
  380. #endif
  381. #endif
  382.     
  383.     if((fp = fopen(file,WRITE_TEXT)) == NULLFILE){
  384.         tprintf("Can't create \"%s\": %s\n",file,sys_errlist[errno]);
  385.         free(file);
  386.         return 0;
  387.     }
  388.     log(m->user,"MBOX upload: %s",file);
  389.     m->state = MBX_UPLOAD;
  390.     tprintf("Send file,  %s",Howtoend);
  391.     for(;;){
  392.     if(mbxrecvline(m) == -1){
  393.             unlink(file);
  394.             break;
  395.         }
  396.     if(*m->line == 0x01){  /* CTRL-A */
  397.             unlink(file);
  398.         tputs(MsgAborted);
  399.             break;
  400.         }
  401.     if(*m->line == CTLZ || !stricmp("/ex",m->line))
  402.             break;
  403.     fputs(m->line,fp);
  404. #if !defined(UNIX) && !defined(__TURBOC__) && !defined(AMIGA)
  405.         /* Needed only if the OS uses a CR/LF
  406.          * convention and putc doesn't do
  407.          * an automatic translation
  408.          */
  409.         if(putc('\r',fp) == EOF)
  410.             break;
  411. #endif
  412.         if(putc('\n',fp) == EOF)
  413.             break;
  414.     }
  415.     free(file);
  416.     fclose(fp);
  417.     return 0;
  418. }
  419.  
  420. int
  421. #ifdef PROTOTYPES
  422. dowhat(int argc,char **argv,void *p)
  423. #else
  424. dowhat(argc,argv,p)
  425. int argc;
  426. char *argv[];
  427. void *p;
  428. #endif
  429. {
  430.     struct mbx *m;
  431.     FILE *fp;
  432.     char *file;
  433.  
  434.     m = (struct mbx *)p;
  435.     if(argc < 2)
  436.         file = strdup(m->path);
  437.     else
  438.         file = pathname(m->path,argv[1]);
  439.     if(!permcheck(m->path,m->privs,RETR_CMD,file)){
  440.     tputs(Noperm);
  441.     mail_error("%s: directory denied\n",m->name);
  442.         return 0;
  443.     }
  444.     m->state = MBX_WHAT;
  445.     if((fp = dir(file,1)) == NULLFILE)
  446.         tprintf("Can't read directory: \"%s\": %s\n",file,sys_errlist[errno]);
  447.     else {
  448. #ifdef MBXTDISC
  449.     stop_timer(&m->tdisc);
  450. #endif
  451.     sendfile(fp,m->user,ASCII_TYPE,0);
  452.     }
  453.     free(file);
  454.     fclose(fp);
  455.     return 0;
  456. }
  457.  
  458. int
  459. #ifdef PROTOTYPES
  460. dozap(int argc,char **argv,void *p)
  461. #else
  462. dozap(argc,argv,p)
  463. int argc;
  464. char *argv[];
  465. void *p;
  466. #endif
  467. {
  468.     struct mbx *m;
  469.     char *file;
  470.  
  471.     m = (struct mbx *)p;
  472.     file = pathname(m->path,argv[1]);
  473.     if(!permcheck(m->path,m->privs,DELE_CMD,file)){
  474.     tputs(Noperm);
  475.     mail_error("%s: zap denied\n",m->name);
  476.         return 0;
  477.     }
  478.     if(unlink(file))
  479.         tprintf("Zap failed: %s\n",sys_errlist[errno]);
  480.     log(m->user,"MBOX Zap: %s",file);
  481.     free(file);
  482.     return 0;
  483. }
  484.  
  485. /*Password protection added - 920118, WG7J */
  486. int
  487. #ifdef PROTOTYPES
  488. dosysop(int argc,char **argv,void *p)
  489. #else
  490. dosysop(argc,argv,p)
  491. int argc;
  492. char *argv[];
  493. void *p;
  494. #endif
  495. {
  496.     struct mbx *m;
  497.     int c;
  498.     int len,pwdc[5],i,valid=0;
  499.     char *cp;
  500.     extern struct cmds DFAR Cmds[];
  501.  
  502.     m = (struct mbx *) p;
  503.     log(m->user,"MBOX: %s attempting SYSOP",m->name);
  504.  
  505.     /*If you want anyone with the password to go sysop-mode
  506.      *comment out the next 4 line ! -WG7J
  507.      */
  508.     if(!(m->privs & SYSOP_CMD)){
  509.     tputs(Noperm);
  510.     mail_error("%s: SYSOP denied !\n",m->name);
  511.         return 0;
  512.     }
  513.  
  514.     /*only if set,
  515.      *check for the password before letting users proceed
  516.      */
  517.     m->state = MBX_SYSOPTRY;
  518.     if((len = strlen(Mbpasswd)) != 0) {;
  519.     for (i=0;i<5;i++)
  520.             tprintf("%d ",(pwdc[i]=RANDOM(len))); /*print the random chars*/
  521.     tputc('\n');
  522.     while(1) {
  523.         c = mbxrecvline(m);
  524.         if(c == EOF || c == -2)
  525.         return 0;
  526.         if(*m->line == '\0')
  527.         break;
  528.         cp = m->line;
  529.         for(i=0;i<5;i++)
  530.         if(*cp++ != Mbpasswd[pwdc[i]])
  531.             break;
  532.         if (i == 5)
  533.         valid = 1;
  534.     }
  535.     if(!valid)
  536.     return 0;
  537.     }
  538.  
  539.     log(m->user,"MBOX: %s is now SYSOP",m->name);
  540.     m->state = MBX_SYSOP;
  541.     tputs("\n\007Type 'exit' to return\n\nBe VERY carefull!!\n");
  542.  
  543.     for(;;){
  544.     tputs("Net> ");
  545.         usflush(Curproc->output);
  546.     if(mbxrecvline(m) < 0)
  547.             break;
  548.         log(m->user,"MBOX sysop: %s",m->line);
  549.     if(cmdparse(Cmds,m->line,NULL) == -2)
  550.         break;
  551.     }
  552.     return 0;
  553. }
  554.  
  555. /* Handle the "*** Done" command when reverse forwarding ends or the
  556.  * "*** LINKED to" command.
  557.  */
  558. int
  559. #ifdef PROTOTYPES
  560. dostars(int argc,char **argv,void *p)
  561. #else
  562. dostars(argc,argv,p)
  563. int argc;
  564. char *argv[];
  565. void *p;
  566. #endif
  567. {
  568.     struct mbx *m;
  569.     int anony = 1;
  570.     int founddigit = 0;
  571.     int oldprivs;
  572.     char *cp;
  573.  
  574.     m = (struct mbx *)p;
  575.  
  576.     /* The "*** LINKED to" command is only allowed to stations with
  577.      * SYSOP privileges to prevent others from obtaining the same.
  578.      */
  579. #ifdef notdef
  580.     if((m->privs & SYSOP_CMD) && argc == 4 && !strcmp(argv[1],"linked")) {
  581. #endif
  582.     /* Allow 'linked to' from anyone, but reset SYSOP priviledges
  583.      * when the sysop-password is not set !
  584.      * Also try to set the new call !
  585.      * Inspired by Kurt, wb5bbw
  586.      * Check for the strange TEXNET linked message !
  587.      * 920220 - WG7J
  588.      */
  589.     if((argc >= 4) && !strcmp(argv[1],"linked") && !strcmp(argv[2],"to") ) {
  590. #ifdef GWTRACE
  591.         log(m->user,"MBOX LINKED: %s changed to %s",m->name,argv[3]);
  592. #endif
  593.     strcpy(m->name,argv[3]);
  594.         oldprivs = m->privs; /*Save this !*/
  595.         /* Try to find the privileges of this user from the userfile */
  596.         if((m->privs = userlogin(m->name,NULLCHAR,&m->path,MBXLINE,
  597.                      &anony)) == -1)
  598.              if((m->privs = userlogin("bbs",NULLCHAR,&m->path,
  599.                       MBXLINE,&anony)) == -1)
  600.               if((m->privs = userlogin("anonymous",NULLCHAR,
  601.                        &m->path,MBXLINE,&anony)) == -1){
  602.                         m->privs = 0;
  603.                         free(m->path);
  604.                         m->path = NULLCHAR;
  605.               }
  606.         if(m->privs & EXCLUDED_CMD)
  607.             return domboxbye(0,NULLCHARP,p);
  608. #ifdef AX25
  609.     /* Set the call */
  610.         for(cp=m->name;*cp != '\0';cp++)
  611.             if(isdigit((int)*cp))
  612.                 break;
  613.         if(*cp != '\0')
  614.             founddigit = 1;
  615.         if( (setcall(m->call,m->name) == -1) || (!founddigit) ) {
  616.             m->privs &= ~AX25_CMD;
  617.             m->privs &= ~NETROM_CMD;
  618.         }
  619. #else
  620.     m->privs &= ~AX25_CMD;
  621.     m->privs &= ~NETROM_CMD;
  622. #endif
  623.     /*Kill ssid in name, if any*/
  624.     if((cp=strchr(m->name,'-')) != NULLCHAR)
  625.         *cp = '\0';
  626.     /*Check if sysop password is set,
  627.          *if not, disallow sysop privs no matter what !
  628.          */
  629.         if(*Mbpasswd == '\0')
  630.             m->privs &= ~SYSOP_CMD;
  631.         /*Check to see if any of NO_READ,NO_SEND or NO_3PARTY were set,
  632.          *if so, dis-allow those no matter what
  633.          *(so that users cannot get priviledges by issuing a ***linked)
  634.          * 920220 - WG7J
  635.          */
  636.         if(oldprivs & NO_SENDCMD)
  637.             m->privs |= NO_SENDCMD;
  638.         if(oldprivs & NO_READCMD)
  639.             m->privs |= NO_READCMD;
  640.         if(oldprivs & NO_3PARTY)
  641.             m->privs |= NO_3PARTY;
  642.  
  643.         tprintf("Oh, hello %s.\n",m->name);
  644. #ifdef MAILCMDS
  645.     changearea(m,m->name);
  646. #endif
  647.     return 0;
  648.     }
  649.     if(argc > 1 && (m->sid & MBX_SID))      /* "*** Done" or similar */
  650.     return -2;
  651.     return -1;
  652. }
  653.  
  654. #ifdef MAILCMDS
  655. int
  656. doarea(argc,argv,p)
  657. int argc;
  658. char *argv[];
  659. void *p;
  660. {
  661.     struct mbx *m;
  662.     char *cp, *area;
  663.     FILE *fp;
  664.     char buf[MBXLINE];
  665.  
  666.     m = (struct mbx *) p;
  667.     if(argc < 2){
  668. #ifdef USERLOG
  669.     if(m->stype == 'N') {
  670.         listnewmail(m);
  671.         return 0;
  672.     }
  673. #endif
  674.     area = strdup(m->area);
  675.         while((cp = strchr(area,'/')) != NULLCHAR)
  676.             *cp = '.';
  677.         tprintf("Current message area is: %s\n\n",area);
  678.         free(area);
  679.  
  680.     tprintf("Available areas are:\n%-15s",m->name);
  681.     if(m->stype == 'F')
  682.         tputs("  Your private mail area\n");
  683.     else
  684.         tputc('\n');
  685.         if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
  686.             return 0;
  687.     if(m->stype == 'F')
  688.         sendfile(fp,m->user,ASCII_TYPE,0);
  689.     else {
  690.         /* send only the area names, not the description */
  691.         while(fgets(buf,MBXLINE,fp) != NULLCHAR) {
  692.         if(buf[0] != '#') { /* skip comments */
  693.             if((cp=strchr(buf,' ')) != NULLCHAR) {
  694.             *cp++ = '\n';
  695.             *cp = '\0';
  696.             }
  697.             if((cp=strchr(buf,'\t')) != NULLCHAR) {
  698.             *cp++ = '\n';
  699.             *cp = '\0';
  700.             }
  701.             tputs(buf);
  702.         }
  703.         }
  704.         tputs("\nType AF to get description of areas\n\n");
  705.     }
  706.     fclose(fp);
  707.         return 0;
  708.     }
  709.     if((m->privs & SYSOP_CMD) || strcmp(m->name,argv[1]) == 0){
  710.         /*Private mail-areas*/
  711.         changearea(m,argv[1]);
  712.         if(m->nmsgs){
  713.             if(!strcmp(m->name,m->area))
  714.         tputs("You have ");
  715.             else {
  716.                 area = strdup(m->area);
  717.                 while((cp = strchr(area,'/')) != NULLCHAR)
  718.                     *cp = '.';
  719.                 tprintf("%s: ",area);
  720.                 free(area);
  721.             }
  722.             tprintf("%d message%s -  %d new.\n", m->nmsgs,
  723.               m->nmsgs == 1 ? " " : "s ", m->newmsgs);
  724.         }
  725.         return 0;
  726.     }
  727.     if(isarea(argv[1])) {
  728.         /*Public mail areas*/
  729.         changearea(m,argv[1]);
  730.         area = strdup(m->area);
  731.         while((cp = strchr(area,'/')) != NULLCHAR)
  732.             *cp = '.';
  733. #ifdef USERLOG
  734.         tprintf("%s: %d message%s -  %d new\n\n",area,m->nmsgs,
  735.             m->nmsgs == 1 ? " " : "s ", m->newmsgs);
  736. #else
  737.     tprintf("%s: %d message%s.\n", area, m->nmsgs,
  738.       m->nmsgs == 1 ? "" : "s");
  739. #endif
  740.     free(area);
  741.     }
  742.     else
  743.         tprintf("No such message area: %s\n",argv[1]);
  744.     return 0;
  745. }
  746.  
  747. /* subroutine to do the actual switch from one area to another */
  748. /* USERLOGGING added by WG7J */
  749. void
  750. changearea(m,area)
  751. struct mbx *m;
  752. char *area;
  753. {
  754.     char *cp;
  755.  
  756. #ifdef USERLOG
  757.     setlastread(m);
  758. #endif
  759.     closenotes(m);
  760.     m->nmsgs = m->newmsgs = m->current = 0;
  761.     strcpy(m->area,area);
  762.     while((cp = strchr(m->area,'.')) != NULLCHAR)
  763.         *cp = '/';
  764.     while((cp = strchr(m->area,'\\')) != NULLCHAR)
  765.         *cp = '/';
  766.  
  767. #ifdef USERLOG
  768.     /* only read last read message-id if this is not a bbs,
  769.      * current area is a public area and not 'help'
  770.      * or area starts with 'sys'
  771.      */
  772.     if(!(m->sid & MBX_SID))
  773.     if( (strcmp(area,"help") && isarea(area)) || !strncmp(m->area,"sys",3) )
  774.         getlastread(m);
  775. #endif
  776.  
  777.     scanmail(m);
  778. }
  779. #endif
  780.  
  781. int
  782. dombtelnet(argc,argv,p)
  783. int argc;
  784. char *argv[];
  785. void *p;
  786. {
  787.     struct mbx *m;
  788.     int s, len, i;
  789.     char dsocket[MAXSOCKSIZE];
  790.     struct sockaddr_in fsocket;
  791.  
  792.     m = (struct mbx *) p;
  793.     fsocket.sin_family = AF_INET;
  794.     if(argc < 3)
  795.         fsocket.sin_port = IPPORT_TELNET;
  796.     else
  797.     fsocket.sin_port = atoip(argv[2]);
  798.  
  799.     if((fsocket.sin_addr.s_addr = resolve(argv[1])) == 0){
  800.         tprintf(Badhost,argv[1]);
  801.     /* Free m->starmsg if set ! - WG7J */
  802.     if(m->startmsg != NULLCHAR) {
  803.         free(m->startmsg);
  804.         m->startmsg = NULLCHAR;
  805.     }
  806.     return 0;
  807.     }
  808.     /* Only local telnets are are allowed to the unprivileged user */
  809.     /* The above is a security hole ! DO NOT allow this anymore ! - WG7J */
  810.  
  811.     /* If the first letter of the command is 'C', then it was
  812.      * the CALL,QUERY,OPERATOR or CONVERS command !
  813.      * Allow these, no matter what.
  814.      * This way, you can give access to the Internet callserver,
  815.      * but disable all other telnets - WG7J
  816.      */
  817.     if(*argv[0] != 'C') {
  818.     if(!(m->privs & TELNET_CMD) /* && !ismyaddr(fsocket.sin_addr.s_addr)*/ ){
  819.         tputs(Noperm);
  820.         mail_error("%s: Telnet denied\n",m->name);
  821.         /* Free m->starmsg if set ! - WG7J */
  822.         /* Shouldn't happen here, but just in case */
  823.         if(m->startmsg != NULLCHAR) {
  824.         free(m->startmsg);
  825.         m->startmsg = NULLCHAR;
  826.         }
  827.         return 0;
  828.     }
  829.     }
  830.     if((s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  831.     tputs(Nosock);
  832.     /* Free m->starmsg if set ! - WG7J */
  833.     if(m->startmsg != NULLCHAR) {
  834.         free(m->startmsg);
  835.         m->startmsg = NULLCHAR;
  836.     }
  837.     return 0;
  838.     }
  839. #ifdef GWTRACE
  840.     log(m->user,"MBOX TELNET: %s to %s:%d",m->name,argv[1],fsocket.sin_port);
  841. #endif
  842.     if(fsocket.sin_port == IPPORT_TTYLINK) {
  843.         m->startmsg = mallocw(80);
  844.         len = MAXSOCKSIZE;
  845.         i = getpeername(m->user,dsocket,&len);
  846.         sprintf(m->startmsg,"*** Incoming call from %s@%s ***\n",
  847.             m->name,i != -1 ? psocket(dsocket): Hostname);
  848.     }
  849.     m->state = MBX_GATEWAY;
  850.     return gw_connect(m,s,(struct sockaddr *)&fsocket,SOCKSIZE);
  851. }
  852.  
  853. int
  854. #ifdef PROTOTYPES
  855. dombfinger(int argc,char **argv,void *p)
  856. #else
  857. dombfinger(argc,argv,p)
  858. int argc;
  859. char *argv[];
  860. void *p;
  861. #endif
  862. {
  863.     struct mbx *m;
  864.     char *host, *user = NULLCHAR, buf[8], *newargv[3];
  865.  
  866.     if(argc > 2){
  867.     tputs("Usage: F user@host  or  F @host  or  F user.\n");
  868.         return 0;
  869.     }
  870.     host = Hostname;
  871.     if(argc == 2){
  872.         if((host = strchr(argv[1], '@')) != NULLCHAR){
  873.             *host = '\0';
  874.             host++;
  875.         } else
  876.             host = Hostname;
  877.         user = argv[1];
  878.     }
  879.     m = (struct mbx *) p;
  880.     m->startmsg = mallocw(80);
  881.     if(user != NULLCHAR)
  882.         sprintf(m->startmsg,"%s\n",user);
  883.     else
  884.         strcpy(m->startmsg,"\n");
  885.     newargv[0] = "t";
  886.     newargv[1] = host;
  887.     sprintf(buf,"%d",IPPORT_FINGER);
  888.     newargv[2] = buf;
  889.     return dombtelnet(3,newargv,p);
  890. }
  891.  
  892. /* Generic mbox gateway code. It sends and frees the contents of m->startmsg
  893.  * when the connection has been established unless it a null pointer.
  894.  */
  895. int
  896. gw_connect(m,s,fsocket,len)
  897. struct mbx *m;
  898. int s;
  899. struct sockaddr *fsocket;
  900. int len;
  901. {
  902.     int c;
  903.     char *cp, *cp1;
  904.     struct proc *child;
  905.     struct gwalarm *gwa;
  906.     char *node, *tocall, whereto[128], buf[80];
  907.     char temp[AXBUF];
  908.     struct nrroute_tab *rp;
  909.  
  910.     sockmode(s,SOCK_ASCII);
  911.     child = newproc("gw supervisor",256,gw_superv,0,Curproc,m,0);
  912.     tputs("Trying...");
  913.     if(m->privs & NO_ESCAPE)
  914.     tputc('\n');
  915.     else {
  916.     tputs("  The escape character is: ");
  917.     if(m->escape < 32)
  918.         tprintf("CTRL-%c\n",m->escape+'A'-1);
  919.     else
  920.         tprintf("'%c'\n",m->escape);
  921.     }
  922.     usflush(Curproc->output);
  923.  
  924.     /*find out where we're going to*/
  925.     tocall = strdup(psocket(fsocket));
  926.     if((cp1 = strchr(tocall,' ')) != NULLCHAR)
  927.         *cp1 = '\0';
  928. #ifdef NETROM
  929.     if(fsocket->sa_family == AF_NETROM) {
  930.     /*find the node alias*/
  931.     setcall(temp,tocall);
  932.     rp = find_nrroute(temp);
  933.     node = strdup(rp->alias);
  934.     if((cp1 = strchr(node,' ')) != NULLCHAR)
  935.             *cp1 = '\0';
  936.     sprintf(whereto,"%s:%s",node,tocall);
  937.     free(node);
  938.     } else
  939. #endif
  940.      strcpy(whereto,tocall);
  941.     free(tocall);
  942.  
  943.     if(connect(s,(char *)fsocket,len) == -1){
  944.         if((cp = sockerr(s)) != NULLCHAR) {
  945.             switch(cp[0]) {
  946.             case 'R':
  947.                 sprintf(buf,"%susy from",
  948.                     (m->family == AF_NETROM)?"B":"*** b");
  949.                 break;
  950.             case 'T':
  951.                 if(m->family != AF_NETROM) {
  952.                     sprintf(buf,"*** timeout with");
  953.                     break;
  954.                 }
  955.             default:
  956.                 sprintf(buf,"%sailure with",
  957.                     (m->family == AF_NETROM)?"F":"*** f");
  958.                 break;
  959.             }
  960.         tprintf("%s%s %s\n\n",
  961.         (m->family == AF_NETROM) ? Mbnrid : "",buf,whereto);
  962.         }
  963.     shutdown(s,2);  /* HB9RWM suggestion */
  964.     close_s(s);
  965.         killproc(child);
  966.     /* Free m->starmsg if set ! - WG7J */
  967.     if(m->startmsg != NULLCHAR) {
  968.         free(m->startmsg);
  969.         m->startmsg = NULLCHAR;
  970.     }
  971.  
  972.     return 0;
  973.     }
  974.     /* The user did not type the escape character */
  975.     killproc(child);
  976.  
  977.     tprintf("%s%sonnected to %s\n",
  978.     (m->family == AF_NETROM) ? Mbnrid : "",
  979.         (m->family == AF_NETROM) ? "C" : "*** c",
  980.     whereto);
  981.  
  982.     if(m->startmsg != NULLCHAR){
  983.         usputs(s,m->startmsg);
  984.         free(m->startmsg);
  985.         m->startmsg = NULLCHAR;
  986.     }
  987.  
  988.     /* Since NOS does not flush the output socket after a certain
  989.      * period of time, we have to arrange that ourselves.
  990.      */
  991.     gwa = (struct gwalarm *) mallocw(sizeof(struct gwalarm));
  992.     gwa->s1 = Curproc->output;
  993.     gwa->s2 = s;
  994.     set_timer(&gwa->t,2*1000L);
  995.     gwa->t.func = gw_alarm;
  996.     gwa->t.arg = (void *) gwa;
  997.     start_timer(&gwa->t);
  998.     /* Fork off the receive process */
  999.     child = newproc("gw in",1024,gw_input,s,m,Curproc,0);
  1000.  
  1001.     for(;;){
  1002.         if((c = recvchar(Curproc->input)) == EOF)
  1003.             break;
  1004.     /* Only check ESCAPE char if that is currently turned on */
  1005.     if( !(m->privs & NO_ESCAPE) && c == m->escape){
  1006.         if(socklen(Curproc->input,0))
  1007.         recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
  1008.             break;
  1009.     }
  1010. #ifdef MBXTDISC
  1011.     if(c == '\n')
  1012.         start_timer(&m->tdisc);
  1013. #endif
  1014.     if(usputc(s,c) == EOF)
  1015.             break;
  1016.     }
  1017.     stop_timer(&gwa->t);
  1018.     free((char *)gwa);
  1019.     close_s(s);
  1020.     killproc(child); /* get rid of the receive process */
  1021.     if(m->family == AF_INET)
  1022.         tprintf("%c%c%c\n",IAC,WONT,TN_ECHO);
  1023. #ifdef TTYCALL
  1024.     if (fsocket->sa_family == AF_INET &&
  1025.         ((struct sockaddr_in *) fsocket)->sin_port == IPPORT_TTYLINK &&
  1026.         ismyaddr((int32)((struct sockaddr_in *) fsocket)->sin_addr.s_addr))
  1027.         return 2;        /* magic success code to avoid BBS chaining */
  1028. #endif
  1029.     return 0;
  1030. }
  1031.  
  1032. void
  1033. gw_input(s,notused,p)
  1034. int s;
  1035. void *notused;
  1036. void *p;
  1037. {
  1038.     int c;
  1039.     struct proc *parent;
  1040.     struct mbx *m;
  1041.     char *cp, *cp1;
  1042.     char response[4];
  1043.  
  1044.     parent = (struct proc *) p;
  1045.     m = (struct mbx *) notused;
  1046.  
  1047.     cp1 = strdup(Mbnrid);
  1048.     if((cp = strchr(cp1,'}')) != NULLCHAR)
  1049.         *cp = '\0';
  1050.     strupr(cp1);
  1051.  
  1052. #ifdef notdef
  1053.     while((c = recvchar(s)) != EOF)
  1054.         tputc(c);
  1055. #endif
  1056.     while((c = recvchar(s)) != EOF){
  1057.         if(c != IAC){
  1058.             tputc((char)c);
  1059.             continue;
  1060.         }
  1061.         /* IAC received, get command sequence */
  1062.         c = recvchar(s);
  1063.         switch(c){
  1064.         case WILL:
  1065.             response[0] = IAC;
  1066.             response[1] = DONT;
  1067.             response[2] = recvchar(s);
  1068.             response[3] = '\0';
  1069.             usputs(s,response);
  1070.             break;
  1071.         case WONT:
  1072.         case DONT:
  1073.             c = recvchar(s);
  1074.             break;
  1075.         case DO:
  1076.             response[0] = IAC;
  1077.             response[1] = WONT;
  1078.             response[2] = recvchar(s);
  1079.             response[3] = '\0';
  1080.             usputs(s,response);
  1081.             break;
  1082.         case IAC:       /* Escaped IAC */
  1083.             usputc(s,IAC);
  1084.             break;
  1085.         }
  1086.     }
  1087.  
  1088.     if((cp = sockerr(s)) != NULLCHAR && m->family != AF_NETROM) {
  1089.         switch(cp[0]) {
  1090.         case 'T':
  1091.         usprintf(m->user,"\n*** %s: Link failure",cp1);
  1092.             break;
  1093.         case 'R':
  1094.             usprintf(m->user,"*** DM received");
  1095.             break;
  1096.         }
  1097.     }
  1098.     usprintf(m->user,"\n%s%seconnected to %s\n\n",
  1099.     (m->family == AF_NETROM) ? Mbnrid : "",
  1100.         (m->family == AF_NETROM) ? "R" : "*** r",
  1101.         cp1);
  1102.  
  1103.     free(cp1);
  1104.     cp1 = NULLCHAR;
  1105.  
  1106.     /* Tell the parent that we are no longer connected */
  1107.     alert(parent,ENOTCONN);
  1108.     pwait(Curproc); /* Now wait to be killed */
  1109. }
  1110.  
  1111. /* Check if the escape character is typed while the parent process is busy
  1112.  * doing other things. 
  1113.  */
  1114. void
  1115. gw_superv(null,proc,p)
  1116. int null;
  1117. void *proc;
  1118. void *p;
  1119. {
  1120.     struct proc *parent;
  1121.     struct mbx *m;
  1122.     int c;
  1123.     parent = (struct proc *) proc;
  1124.     m = (struct mbx *) p;
  1125.     while((c = recvchar(Curproc->input)) != EOF)
  1126.         if(c == m->escape){
  1127.             /* flush anything in the input queue */
  1128.             if(socklen(Curproc->input,0))
  1129.                 recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
  1130.             break;
  1131.         }
  1132.     alert(parent,EINTR);     /* Tell the parent to quit */
  1133.     pwait(Curproc);          /* Please kill me */
  1134. }
  1135.  
  1136. void
  1137. gw_alarm(p)
  1138. void *p;
  1139. {
  1140.     struct gwalarm *gwa = (struct gwalarm *)p;
  1141.     char oldbl;
  1142.     struct usock *up;
  1143.  
  1144.     /* Flush sockets s1 and s2, but first make sure that the socket
  1145.      * is set to non-blocking mode, to prevent the flush from blocking
  1146.      * if the high water mark has been reached.
  1147.      */
  1148.     if((up = itop(gwa->s1)) != NULLUSOCK) {
  1149.         oldbl = up->noblock;
  1150.         up->noblock = 1;
  1151.         usflush(gwa->s1);
  1152.         up->noblock = oldbl;
  1153.     }
  1154.     if((up = itop(gwa->s2)) != NULLUSOCK) {
  1155.         oldbl = up->noblock;
  1156.         up->noblock = 1;
  1157.         usflush(gwa->s2);
  1158.         up->noblock = oldbl;
  1159.     }
  1160.     start_timer(&gwa->t);
  1161. }
  1162.  
  1163. #ifdef MAILCMDS
  1164.  
  1165. /* States for send line parser state machine */
  1166. #define         LOOK_FOR_USER           2
  1167. #define         IN_USER                 3
  1168. #define         AFTER_USER              4
  1169. #define         LOOK_FOR_HOST           5
  1170. #define         IN_HOST                 6
  1171. #define         AFTER_HOST              7
  1172. #define         LOOK_FOR_FROM           8
  1173. #define         IN_FROM                 9
  1174. #define         AFTER_FROM              10
  1175. #define         LOOK_FOR_MSGID          11
  1176. #define         IN_MSGID                12
  1177. #define         FINAL_STATE             13
  1178. #define         ERROR_STATE             14
  1179.  
  1180. /* Prepare the addressee.  If the address is bad, return -1, otherwise
  1181.  * return 0
  1182.  */
  1183.  
  1184. int
  1185. #ifdef PROTOTYPES
  1186. mbx_to(int argc,char **argv,void *p)
  1187. #else
  1188. mbx_to(argc,argv,p)
  1189. int argc;
  1190. char *argv[];
  1191. void *p;
  1192. #endif
  1193. {
  1194.     register char *cp;
  1195.     int state, i;
  1196.     char *user, *host, *from, *msgid;
  1197.     int userlen = 0, hostlen = 0, fromlen = 0, msgidlen = 0;
  1198.     struct mbx *m;
  1199.  
  1200.     m = (struct mbx *)p;
  1201.     /* Free anything that might be allocated
  1202.      * since the last call to mbx_to() or mbx_reply()
  1203.      */
  1204.     free(m->to);
  1205.     m->to = NULLCHAR;
  1206.     free(m->tofrom);
  1207.     m->tofrom = NULLCHAR;
  1208.     free(m->tomsgid);
  1209.     m->tomsgid = NULLCHAR;
  1210.     free(m->origto);
  1211.     m->origto = NULLCHAR;
  1212.     free(m->origbbs);
  1213.     m->origbbs = NULLCHAR;
  1214.     free(m->subject);
  1215.     m->subject = NULLCHAR;
  1216.     free(m->date);
  1217.     m->date = NULLCHAR;
  1218.  
  1219.     if(argc == 1)
  1220.         return -1;
  1221. #ifdef __GNUC__
  1222.     user = 0;        /* shut gcc warnings off */
  1223.     host = 0;
  1224.     from = 0;
  1225.     msgid = 0;
  1226. #endif
  1227.     i = 1;
  1228.     cp = argv[i];
  1229.     state = LOOK_FOR_USER;
  1230.     while(state < FINAL_STATE){
  1231. #ifdef MBDEBUG
  1232.         tprintf("State is %d, char is %c\n", state, *cp);
  1233. #endif
  1234.         switch(state){
  1235.         case LOOK_FOR_USER:
  1236.             if(*cp == '@' || *cp == '<' || *cp == '$'){
  1237.                 state = ERROR_STATE;            /* no user */
  1238.             } else {
  1239.                 user = cp;                      /* point at start */
  1240.                 userlen++;                      /* start counting */
  1241.                 state = IN_USER;
  1242.             }
  1243.             break;
  1244.         case IN_USER:
  1245.             switch(*cp){
  1246.             case '\0':
  1247.                 state = AFTER_USER;             /* done with username */
  1248.                 break;
  1249.             case '@':
  1250.                 state = LOOK_FOR_HOST;          /* hostname should follow */
  1251.                 break;
  1252.             case '<':
  1253.                 state = LOOK_FOR_FROM;          /* from name should follow */
  1254.                 break;
  1255.             case '$':
  1256.                 state = LOOK_FOR_MSGID; /* message id should follow */
  1257.                 break;
  1258.             default:
  1259.                 userlen++;                      /* part of username */
  1260.             }
  1261.             break;
  1262.         case AFTER_USER:
  1263.             switch(*cp){
  1264.             case '@':
  1265.                 state = LOOK_FOR_HOST;          /* hostname follows */
  1266.                 break;
  1267.             case '<':
  1268.                 state = LOOK_FOR_FROM;          /* fromname follows */
  1269.                 break;
  1270.             case '$':
  1271.             state = LOOK_FOR_MSGID; /* message id follows */
  1272.                 break;
  1273.             default:
  1274.                 state = ERROR_STATE;
  1275.             }
  1276.             break;
  1277.         case LOOK_FOR_HOST:
  1278.             if(*cp == '@' || *cp == '<' || *cp == '$'){
  1279.                 state = ERROR_STATE;
  1280.                 break;
  1281.             }
  1282.             if(*cp == '\0')
  1283.                 break;
  1284.             host = cp;
  1285.             hostlen++;
  1286.             state = IN_HOST;
  1287.             break;
  1288.         case IN_HOST:
  1289.             switch(*cp){
  1290.             case '\0':
  1291.                 state = AFTER_HOST;             /* found user@host */
  1292.                 break;
  1293.             case '@':
  1294.                 state = ERROR_STATE;            /* user@host@? */
  1295.                 break;
  1296.             case '<':
  1297.                 state = LOOK_FOR_FROM;          /* fromname follows */
  1298.                 break;
  1299.             case '$':
  1300.                 state = LOOK_FOR_MSGID; /* message id follows */
  1301.                 break;
  1302.             default:
  1303.                 hostlen++;
  1304.             }
  1305.             break;
  1306.         case AFTER_HOST:
  1307.             switch(*cp){
  1308.             case '@':
  1309.                 state = ERROR_STATE;            /* user@host @ */
  1310.                 break;
  1311.             case '<':
  1312.                 state = LOOK_FOR_FROM;          /* user@host < */
  1313.                 break;
  1314.             case '$':
  1315.                 state = LOOK_FOR_MSGID; /* user@host $ */
  1316.                 break;
  1317.             default:
  1318.                 state = ERROR_STATE;            /* user@host foo */
  1319.             }
  1320.             break;
  1321.         case LOOK_FOR_FROM:
  1322.             if(*cp == '@' || *cp == '<' || *cp == '$'){
  1323.                 state = ERROR_STATE;
  1324.                 break;
  1325.             }
  1326.             if(*cp == '\0')
  1327.                 break;
  1328.             from = cp;
  1329.             fromlen++;
  1330.             state = IN_FROM;
  1331.             break;
  1332.         case IN_FROM:
  1333.             switch(*cp){
  1334.             case '\0':
  1335.                 state = AFTER_FROM;             /* user@host <foo */
  1336.                 break;
  1337.             case '<':
  1338.                 state = ERROR_STATE;            /* user@host <foo< */
  1339.                 break;
  1340.             case '$':
  1341.                 state = LOOK_FOR_MSGID; /* message id follows */
  1342.                 break;
  1343.             default:
  1344.                 fromlen++;
  1345.             }
  1346.             break;
  1347.         case AFTER_FROM:
  1348.             switch(*cp){
  1349.             case '@':                               /* user@host <foo @ */
  1350.             case '<':                               /* user@host <foo < */
  1351.                 state = ERROR_STATE;
  1352.                 break;
  1353.             case '$':
  1354.                 state = LOOK_FOR_MSGID; /* user@host <foo $ */
  1355.                 break;
  1356.             default:
  1357.                 state = ERROR_STATE;            /* user@host foo */
  1358.             }
  1359.             break;
  1360.         case LOOK_FOR_MSGID:
  1361.             if(*cp == '\0')
  1362.                 break;
  1363.             msgid = cp;
  1364.             msgidlen++;
  1365.             state = IN_MSGID;
  1366.             break;
  1367.         case IN_MSGID:
  1368.             if(*cp == '\0')
  1369.                 state = FINAL_STATE;
  1370.             else
  1371.                 msgidlen++;
  1372.             break;
  1373.         default:
  1374.             /* what are we doing in this state? */
  1375.             state = ERROR_STATE;
  1376.         }
  1377.         if(*(cp) == '\0'){
  1378.             ++i;
  1379.             if(i < argc)
  1380.             cp = argv[i];
  1381.             else break;
  1382.         } else
  1383.             ++cp;
  1384.     }
  1385.     if(state == ERROR_STATE || state == LOOK_FOR_HOST
  1386.      || state == LOOK_FOR_FROM || state == LOOK_FOR_MSGID)
  1387.         return -1;              /* syntax error */
  1388.  
  1389.     m->to = mallocw((unsigned)userlen + hostlen + 2);
  1390.  
  1391.     strncpy(m->to, user, (unsigned)userlen);
  1392.     m->to[userlen] = '\0';
  1393.  
  1394.     if(hostlen){
  1395.         m->to[userlen] = '@';
  1396.         strncpy(m->to + userlen + 1, host, (unsigned)hostlen);
  1397.         m->to[userlen + hostlen + 1] = '\0';
  1398.     }
  1399.     if(fromlen){
  1400.         m->tofrom = mallocw((unsigned)fromlen + 1);
  1401.         strncpy(m->tofrom, from, (unsigned)fromlen);
  1402.         m->tofrom[fromlen] = '\0';
  1403.     }
  1404.     if(msgidlen){
  1405.         m->tomsgid = mallocw((unsigned)msgidlen + 1);
  1406.         strncpy(m->tomsgid, msgid, (unsigned)msgidlen);
  1407.         m->tomsgid[msgidlen] = '\0';
  1408.     }
  1409.     return 0;
  1410. }
  1411.  
  1412. /* This opens the data file and writes the mail header into it.
  1413.  * Returns 0 if OK, and -1 if not.
  1414.  */
  1415.  
  1416. int
  1417. #ifdef PROTOTYPES
  1418. mbx_data(struct mbx *m,struct list *cclist,char *extra)
  1419. #else
  1420. mbx_data(m,cclist,extra)
  1421. struct mbx *m;
  1422. struct list *cclist;    /* list of carbon copy recipients */
  1423. char *extra;        /* optional extra header lines */
  1424. #endif
  1425. {
  1426.     time_t t;
  1427.     struct list *ap;
  1428.     int cccnt = 0;
  1429.     
  1430. #ifdef notdef
  1431.     time(&t);
  1432. /*These 2 lines get added again when the smtp-server handles the mail
  1433.  *not really needed - WG7J
  1434.  */
  1435.     fprintf(m->tfile,Hdrs[RECEIVED]);
  1436.     if(m->tofrom != NULLCHAR)
  1437.         fprintf(m->tfile,"from %s ",m->name);
  1438.     fprintf(m->tfile,"by %s (%s)\n\tid AA%ld ; %s",
  1439.     Hostname, Version, get_msgid(),ptime(&t));
  1440. #endif
  1441.  
  1442.     /* If m->date is set, use this one (comes from bbs-forwarded mail) */
  1443.     if(m->date != NULLCHAR)
  1444.     fprintf(m->tfile,"%s%s",Hdrs[DATE],m->date);
  1445.     else {
  1446.     time(&t);
  1447.     fprintf(m->tfile,"%s%s",Hdrs[DATE],ptime(&t));
  1448.     }
  1449.  
  1450.     /* Bulletin ID, if any */
  1451.     fprintf(m->tfile,Hdrs[MSGID]);
  1452.     if(m->tomsgid)
  1453.         fprintf(m->tfile,"<%s@%s.bbs>\n", m->tomsgid, m->name);
  1454.     else
  1455.         fprintf(m->tfile,"<%ld@%s>\n",get_msgid(), Hostname);
  1456.  
  1457.     /* From : , could use 'real bbs address', if origbbs is set */
  1458.     fprintf(m->tfile,Hdrs[FROM]);
  1459.     if(m->tofrom) {  /* BBS style '< call' */
  1460.     if(m->origbbs != NULLCHAR)
  1461.         fprintf(m->tfile,"%s@%s\n",m->tofrom,m->origbbs);
  1462.     else
  1463.         fprintf(m->tfile,"%s%%%s@%s\n",m->tofrom, m->name, Hostname);
  1464.     } else {
  1465.     if(m->origbbs != NULLCHAR)
  1466.         fprintf(m->tfile,"%s@%s\n",m->name,m->origbbs);
  1467.     else
  1468.         fprintf(m->tfile,"%s@%s\n",m->name,Hostname);
  1469.     }
  1470.  
  1471.     fprintf(m->tfile,"%s%s\n",Hdrs[TO],m->origto != NULLCHAR ? m->origto : m->to);
  1472.  
  1473.     /* Write Cc: line */
  1474.     for(ap = cclist; ap != NULLLIST; ap = ap->next) {
  1475.         if(cccnt == 0){
  1476.             fprintf(m->tfile,"%s",Hdrs[CC]);
  1477.             cccnt = 4;
  1478.         }
  1479.         else {
  1480.                fprintf(m->tfile,", ");
  1481.                cccnt += 2;
  1482.         }
  1483.         if(cccnt + strlen(ap->val) > 80 - 3) {
  1484.                fprintf(m->tfile,"\n    ");
  1485.                cccnt = 4;
  1486.         }
  1487.         fputs(ap->val,m->tfile);
  1488.         cccnt += strlen(ap->val);
  1489.     }
  1490.     if(cccnt)
  1491.         fputc('\n',m->tfile);
  1492.     fprintf(m->tfile,"%s%s\n",Hdrs[SUBJECT],m->subject);
  1493.     if(!isspace(m->stype) && ((m->stype != 'R' && m->stype != 'F') ||
  1494.       (m->sid & MBX_SID) !=0))
  1495.           fprintf(m->tfile,"%s%c\n", Hdrs[BBSTYPE],m->stype);
  1496.  
  1497. #ifdef notdef
  1498.     /*not really needed, the 'From <user%fwdbbs@host>' shows this too!*/
  1499.     /* Also store the 'real smtp from' address */
  1500.     if((m->tofrom != NULLCHAR) && (m->origbbs != NULLCHAR))
  1501.     fprintf(m->tfile,"%s%s%%%s@%s\n",Hdrs[XFROM],m->tofrom,m->name, Hostname);
  1502. #endif
  1503.  
  1504.     if(extra != NULLCHAR)
  1505.         fprintf(m->tfile,extra);
  1506.  
  1507.     return 0;
  1508. }
  1509.  
  1510. /* Returns true if string is in history file or if string appears to be a
  1511.  * message id generated by our system.
  1512.  */
  1513. int
  1514. #ifdef PROTOTYPES
  1515. msgidcheck(char *string)
  1516. #else
  1517. msgidcheck(string)
  1518. char *string;
  1519. #endif
  1520. {
  1521.      FILE *fp;
  1522.      char buf[LINELEN], *cp;
  1523.      if(string == NULLCHAR)
  1524.       return 0;
  1525.      /* BID's that we have generated ourselves are not kept in the history
  1526.       * file. Such BID's are in the nnnn_hhhh form, where hhhh is a part of
  1527.       * our hostname, truncated so that the BID is no longer than 11
  1528.       * characters.
  1529.       */
  1530.      if((cp = strchr(string,'_')) != NULLCHAR && *(cp+1) != '\0' && 
  1531.     strnicmp(cp+1,Hostname,strlen(cp+1)) == 0)
  1532.       return 1;
  1533.  
  1534.      if((fp = fopen(Historyfile,READ_TEXT)) == NULLFILE)
  1535.       return 0;
  1536.      while(fgets(buf,LINELEN,fp) != NULLCHAR) {
  1537.     rip(buf);
  1538.     /* Get rid of following spaces or tabs, to separate the
  1539.      * bid and it's time stamp entry - WG7J
  1540.      */
  1541.     if( ((cp=strchr(buf,' ')) != NULLCHAR) || \
  1542.         ((cp=strchr(buf,'\t')) != NULLCHAR) )
  1543.         *cp = '\0';
  1544.     if(stricmp(string,buf) == 0) {    /* found */
  1545.         fclose(fp);
  1546.         return 1;
  1547.     }
  1548.     }
  1549.     fclose(fp);
  1550.     return 0;
  1551. }
  1552. #endif /* MAILCMDS */
  1553.  
  1554. /* uuencode a file -- translated from C++; both versions copyright 1990
  1555.    by David R. Evans, G4AMJ/NQ0I
  1556. */
  1557.  
  1558.  
  1559. int
  1560. uuencode(infile,s,infilename)
  1561. FILE *infile;
  1562. int s;                  /* output socket */
  1563. char *infilename;
  1564. {
  1565.   int n_read_so_far = 0, n_written_so_far = 0, in_chars, n, mode = 0755;
  1566.   unsigned long cnt = 0;
  1567.   unsigned char in[3], out[4], line[100];
  1568. #ifdef UNIX
  1569.   struct stat stb;
  1570.   
  1571.   if(stat(infilename,&stb) != -1)
  1572.        mode = stb.st_mode & 0777;       /* get real file protection mode */
  1573. #endif
  1574.   usprintf(s, "begin %03o %s\n", mode, infilename);
  1575.  
  1576.   /* do the encode */
  1577.  for(;;){       
  1578.     in_chars = fread(in, 1, 3, infile);
  1579.     out[0] = in[0] >> 2;
  1580.     out[1] = in[0] << 6;
  1581.     out[1] = out[1] >> 2;
  1582.     out[1] = out[1] | (in[1] >> 4);
  1583.     out[2] = in[1] << 4;
  1584.     out[2] = out[2] >> 2;
  1585.     out[2] = out[2] | (in[2] >> 6);
  1586.     out[3] = in[2] << 2;
  1587.     out[3] = out[3] >> 2;
  1588.     for (n = 0; n < 4; n++)
  1589.       out[n] += ' ';
  1590.     n_read_so_far += in_chars;
  1591.     for (n = 0; n < 4; n++)
  1592.       line[n_written_so_far++] = out[n];
  1593.     if (((in_chars != 3) || (n_written_so_far == 60)) && n_read_so_far > 0) {
  1594.       line[(n_read_so_far + 2) / 3 * 4] = '\0';
  1595.       
  1596.       usprintf(s,"%c%s\n",n_read_so_far + ' ', line);
  1597.       cnt += n_read_so_far;
  1598.       n_read_so_far = 0;
  1599.       n_written_so_far = 0;
  1600.     }
  1601.     if (in_chars == 0)
  1602.       break;
  1603.   }
  1604.   if (usprintf(s," \nend\nsize %lu\n", cnt) == EOF)
  1605.     return 1;
  1606.   return 0;
  1607. }
  1608.  
  1609. #ifdef MAILCMDS
  1610. /* Attempt to determine if this is third-pary mail. */
  1611. int
  1612. #ifdef PROTOTYPES
  1613. thirdparty(struct mbx *m)
  1614. #else
  1615. thirdparty(m)
  1616. struct mbx *m;
  1617. #endif
  1618. {
  1619.     char buf[MBXLINE], *cp, *rp;
  1620.     FILE *fp;
  1621.  
  1622.     if(strchr(m->to,'@') != NULLCHAR || strchr(m->to,'%') != NULLCHAR
  1623.             || strchr(m->to,'!') != NULLCHAR)
  1624.         return 0;
  1625.  
  1626.     rp = strdup(Hostname);
  1627.  
  1628.     if((cp = strchr(rp, '.')) != NULLCHAR)
  1629.         *cp = '\0';
  1630.  
  1631.     if(stricmp(m->to,rp) == 0){
  1632.         free(rp);
  1633.         return -1;
  1634.     }
  1635.     free(rp);
  1636.  
  1637.     if(stricmp(m->to,"sysop") == 0)
  1638.         return -1;
  1639.  
  1640.     if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
  1641.         return 0;
  1642.  
  1643.     while(fgets(buf,MBXLINE,fp) != NULLCHAR){
  1644.         /* The first word on each line is all that matters */
  1645.         if((cp = strchr(buf, ' ')) != NULLCHAR)
  1646.             *cp = '\0';
  1647.         if((cp = strchr(buf,'\t')) != NULLCHAR)
  1648.             *cp = '\0';
  1649.         if(stricmp(m->to,buf) == 0){
  1650.             fclose(fp);
  1651.             return -1;
  1652.         }
  1653.     }
  1654.     fclose(fp);
  1655.     return 0;
  1656. }
  1657. #endif
  1658.  
  1659. extern int Mbconverse;
  1660.  
  1661. int
  1662. #ifdef PROTOTYPES
  1663. dombconnect(int argc,char **argv,void *p)
  1664. #else
  1665. dombconnect(argc,argv,p)
  1666. int argc;
  1667. char *argv[];
  1668. void *p;
  1669. #endif
  1670. {
  1671.     struct mbx *m;
  1672.     struct nrroute_tab *np;
  1673.     int ndigis,i,s;
  1674.     struct sockaddr_nr lsocket,fsocket;
  1675.     struct sockaddr_ax alsocket;    /*the local socket*/
  1676.     struct sockaddr_ax afsocket;    /*the remote socket*/
  1677.     struct iface *ifp;
  1678.     char alias[AXBUF];
  1679.     char local_call[AXALEN];
  1680.     char digis[MAXDIGIS][AXALEN];
  1681.     char target[AXALEN];
  1682.  
  1683.     m = (struct mbx *) p;
  1684.  
  1685.     if(argc == 1){
  1686. #ifdef  CONVERS
  1687.     if(!Mbconverse) {
  1688.         tputs("Convers server not enabled\n");
  1689.         return 0;
  1690.     }
  1691.     if(m->privs & NO_CONVERS) {
  1692.         tputs(Noperm);
  1693.         mail_error("%s: converse denied\n",m->name);
  1694.         return 0;
  1695.     }
  1696. #ifdef GWTRACE
  1697.     log(m->user,"MBOX CONVERS: %s",m->name);
  1698. #endif
  1699.     m->state = MBX_CONVERS;
  1700.     mbox_converse(m);
  1701. #else
  1702.     dombconnecthelp();
  1703. #endif
  1704.         return 0;
  1705.     }
  1706.  
  1707.     if(MBSecure)
  1708. #ifdef NETROM
  1709.     if((m->family != AF_AX25) && (m->family != AF_NETROM)) {
  1710. #else
  1711.         if(m->family != AF_AX25) {
  1712. #endif
  1713.         tputs(Noperm);
  1714.         mail_error("%s: gateway denied (secure mode)\n",m->name);
  1715.         return 0;
  1716.     }
  1717.  
  1718.     if (argc == 2) {
  1719. #ifndef NETROM
  1720.         dombconnecthelp();
  1721.         return 0;
  1722.     }
  1723. #else
  1724.     /*NETROM connection wanted*/
  1725.     if(!(m->privs & NETROM_CMD)) {
  1726.         tputs(Noperm);
  1727.         mail_error("%s: NETROM gate to %s denied\n",m->name,argv[1]);
  1728.         return 0;
  1729.     }
  1730.  
  1731.     if(Nr_iface == NULLIF){
  1732.         tputs("NET/ROM not activated.\n\n");
  1733.         return 0;
  1734.     }
  1735.     /* See if the requested destination is a known alias or call,
  1736.      * use it if it is.  Otherwize give an error message.
  1737.      */
  1738.     putalias(alias,argv[1],0);
  1739.     strupr(argv[1]);    /*make sure it's upper case*/
  1740.     if((np = find_nrboth(alias,argv[1])) == NULLNRRTAB){
  1741.         /*no such call or node alias*/
  1742.         tputs("no such node\n\n");
  1743.         dombconnecthelp();
  1744.         dombports(0,NULL,p);
  1745.         return 0;
  1746.     }
  1747.  
  1748.     if((s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  1749.         tputs(Nosock);
  1750.         return 0;
  1751.     }
  1752. #ifdef GWTRACE
  1753.         log(m->user,"MBOX NETROM: %s to %s",m->name,argv[1]);
  1754. #endif
  1755.         lsocket.nr_family = AF_NETROM;
  1756.  
  1757.     /* Set up our local username, bind would use Mycall instead */
  1758.     memcpy(lsocket.nr_addr.user,m->call,AXALEN);
  1759.     /* Set up our source address */
  1760.     memcpy(lsocket.nr_addr.node,Nr_iface->hwaddr,AXALEN);
  1761.  
  1762.     bind(s,(char *)&lsocket,sizeof(struct sockaddr_nr));
  1763.  
  1764.     memcpy(fsocket.nr_addr.user,np->call,AXALEN);
  1765.     memcpy(fsocket.nr_addr.node,np->call,AXALEN);
  1766.     fsocket.nr_family = AF_NETROM;
  1767.     m->state = MBX_GATEWAY;
  1768.     return gw_connect(m,s,(struct sockaddr *)&fsocket, sizeof(struct sockaddr_nr));
  1769.     }
  1770. #endif /*NETROM*/
  1771.  
  1772. #ifdef AX25
  1773.     if(argc > 2) {
  1774.     /*AX25 gateway connection wanted*/
  1775.     if(!(m->privs & AX25_CMD)) {
  1776.         tputs(Noperm);
  1777.         mail_error("%s: AX.25 gate to %s on %s denied\n",m->name,argv[2],argv[1]);
  1778.         return 0;
  1779.     }
  1780.  
  1781.     if( ((ifp = if_lookup(argv[1])) == NULLIF) ||
  1782.        ((ifp->flags & HIDE_PORT) && !(m->privs & SYSOP_CMD)) ||
  1783.         (ifp->type != CL_AX25) ) {
  1784.         tprintf("Unknown port %s\n",argv[1]);
  1785.         dombports(0,NULL,p);
  1786.         return 0;
  1787.     }
  1788.     if(setcall(target,argv[2]) == -1){
  1789.         tprintf("Bad call %s\n",argv[2]);
  1790.         return 0;
  1791.     }
  1792.     /* If digipeaters are given, put them in the routing table */
  1793.     if(argc > 3){
  1794.         ndigis = argc - 3;
  1795.         if(ndigis > MAXDIGIS){
  1796.         tputs("Too many digipeaters\n");
  1797.         return 0;
  1798.         }
  1799.         for(i=0;i<ndigis;i++){
  1800.         if(setcall(digis[i],argv[i+3]) == -1){
  1801.             tprintf("Bad digipeater %s\n",argv[i+3]);
  1802.             return 0;
  1803.         }
  1804.         }
  1805.         if(ax_add(target,AX_AUTO,digis,ndigis,ifp) == NULLAXR){
  1806.         tputs("AX25 route add failed\n");
  1807.         return 0;
  1808.         }
  1809.     }
  1810.     if((s = socket(AF_AX25,SOCK_STREAM,0)) == -1){
  1811.         tputs(Nosock);
  1812.         return 0;
  1813.     }
  1814. #ifdef GWTRACE
  1815.         log(m->user,"MBOX AX25: %s to %s on %s",m->name,argv[2],argv[1]);
  1816. #endif
  1817.  
  1818.     /*fill in the known stuff*/
  1819.     alsocket.sax_family = afsocket.sax_family= AF_AX25;
  1820.     
  1821.     /*the remote call to connect to*/
  1822.     setcall(afsocket.ax25_addr,argv[2]);
  1823.  
  1824.     /*the outgoing interface*/
  1825.     strncpy(afsocket.iface,argv[1],ILEN);
  1826.  
  1827.     /*now set local user call, invert ssid*/
  1828.     memcpy(local_call,m->call,AXALEN);
  1829.     local_call[AXALEN-1] ^= 0x1e;
  1830.     memcpy(alsocket.ax25_addr,local_call,AXALEN);
  1831.     /*and bind it (otherwize Mycall will be used!)*/
  1832.     bind(s,(char *)&alsocket,sizeof(struct sockaddr_ax));
  1833.     m->state = MBX_GATEWAY;
  1834.     return gw_connect(m,s,(struct sockaddr *)&afsocket, sizeof(struct sockaddr_ax));
  1835.     }
  1836. #endif /* AX25 */
  1837.  
  1838.     return 0;
  1839. }
  1840.  
  1841. #endif /* MAILBOX */
  1842.